package register;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Register implements Komponente {
	private List<Komponente>kinder;
	private String name;
	private int rang;
	
	/**
	 * Konstruiert eine Register-Komponente.
	 * @param name
	 * @param rang
	 */
	public Register(String name, int rang) {
		kinder = new ArrayList<Komponente>();
		this.name = name;
		this.rang = rang;
	}
	
	/**
	 * Haengt dem Register mit angegebenen Namen ein neues Register an.
	 * @param registerName		Name des vorhandenen Registers
	 * @param registerNameNeu	Name des hinzuzufuegenden Registers
	 */
	public void registerHinzufuegen(String registerName, String registerNameNeu) {
		Komponente k = this.sucheRegister(registerName);
		
		if (k == null) {
			System.out.println("Hinzufügen fehlgeschlagen");
			return;
		}
		
		k.hinzufuegen(new Register(registerNameNeu, k.getRang()+1));
		System.out.println("Erfolgreich hinzugefügt!");
		
	}
	
	/**
	 * Haengt dem Register mit angegebenen Namen ein neues Mitglied an.
	 * @param registerName	Name des vorhandnen Registers
	 * @param mitgliedName	Name des hinzuzufuegenden Mitglieds
	 */
	public void mitgliedHinzufuegen(String registerName, String mitgliedName) {
		Komponente k = this.sucheRegister(registerName);
		
		if (k == null) {
			System.out.println("Hinzufügen fehlgeschlagen");
			return;
		}
		
		k.hinzufuegen(new Mitglied(mitgliedName, k.getRang()+1));
		System.out.println("Erfolgreich hinzugefügt!");
	}
	
	/**
	 * Fuegt eine Kind-Komponente k hinzu.
	 * @param k	hinzuzufuegende Komponente
	 */
	@Override
	public void hinzufuegen(Komponente k) {
		kinder.add(k);
	}
	
	/**
	 * Loescht die Kind-Komponente k.
	 * @param k	zu loeschende Komponente
	 */
	@Override
	public void loeschen(Komponente k) {
		kinder.remove(k);
	}
	
	/**
	 * Durchsucht die Struktur, ausgehend vom aktuellen Register, nach
	 * einem Register mit dem angegebenen Namen. Dabei wird ein
	 * Tiefensuche-Algorithmus verwendet.
	 * @param name	Name des zu suchenden Registers
	 */
	@Override
	public Komponente sucheRegister(String name) {
		Stack<Komponente> s = new Stack<Komponente>();
		s.push(this);
		
		while(!s.empty()) {
			Komponente r = s.pop();
			
			if (r.istRegister()) {
				if (r.getName().equals(name))
					return r;
				
				for(Komponente k:r.getKinder())
					s.push(k);
			}
		}
		System.out.println("Register nicht gefunden.");
		return null;
	}
	
	/**
	 * Verschiebt ein Mitglied einen Rang nach oben.
	 * @param id	ID des zu befoerdenen Mitglieds
	 */
	public void mitgliedBefoerdern(int id) {
		Stack<Komponente> s = new Stack<Komponente>();
		Komponente vorgaenger = null;
		s.push(this);
		
		while(!s.empty()) {
			Komponente r = s.pop();
			
			if (r.istRegister()) {
				for(Komponente k:r.getKinder()) {
					if (!k.istRegister() && k.getId() == id) {
						if (vorgaenger == null || k.getRang() < 2) {
							System.out.println("Beförderung fehlgeschlagen!");
							return;
						}
						
						k.setRang(k.getRang()-1);
						vorgaenger.hinzufuegen(k);
						r.loeschen(k);
						System.out.println("Beförderung erfolgreich!");
						return;
					}
						
					vorgaenger = r;	
					s.push(k);
				}
			}
		}
		System.out.println("Mitglied nicht gefunden!");
	}
	
	/**
	 * Prueft, ob die Komponente ein Register ist.
	 * @return	true wenn ja, false wenn nicht
	 */
	@Override
	public boolean istRegister() {
		return true;
	}

	/**
	 * Liefert den Namen des Registers.
	 */
	@Override
	public String getName() {
		return name;
	}
	
	/**
	 * Liefert den Rang des Registers.
	 * @return rang
	 */
	@Override
	public int getRang() {
		return rang;
	}
	
	/**
	 * Liefert die ID des Registers.
	 * Die ID eines Registers ist immer -1.
	 * @return -1
	 */
	@Override
	public int getId() {
		return -1;
	}
	
	/**
	 * Liefert die Kind-Komponenten des Registers.
	 * @return kinder
	 */
	@Override
	public List<Komponente> getKinder() {
		return kinder;
	}
	
	/**
	 * Setzt den Rang des Registers.
	 */
	@Override
	public void setRang(int rang) {
		this.rang = rang;
	}
	
	/**
	 * Gibt alle Mitglieder-Komponeneten auf den Bildschirm
	 * aus, die zu diesem Register gehoeren.
	 */
	@Override
	public void printMitglieder() {
		for (Komponente k:kinder) {
			if (!k.istRegister())
				System.out.println(k);
			else
				k.printMitglieder();
		}
	}
	
	/**
	 * Gibt die Struktur (Register und Mitglieder) auf dem
	 * Bildschirm aus, die zu diesem Register gehoeren und
	 * formatiert die Ausgabe.
	 */
	@Override
	public void printStruktur() {
		StringBuffer tabs = new StringBuffer();
		
		for (int i=0; i<rang; i++)
			tabs.append("    ");
		
		System.out.println(tabs.toString()+this.toString()+" [");
		
		for (Komponente k:kinder)
			k.printStruktur();		
		
		System.out.println(tabs.toString()+"]");
	}
	
	@Override
	public String toString() {
		return name+" Rang:"+rang;
	}
}
